﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using GitPuller.Configurations;
using NewLife.Log;

namespace GitPuller
{
    internal class Program
    {
        public static List<Task> Running { get; } = new List<Task>();
        public static ConcurrentQueue<Func<Task>> Queue { get; } = new ConcurrentQueue<Func<Task>>();
        private static async Task GitPull(string dir)
        {
            var info = new ProcessStartInfo("git")
            {
                CreateNoWindow = true,
                Arguments = "pull",
                RedirectStandardError = true,
                RedirectStandardOutput = true,
                UseShellExecute = false,
                WorkingDirectory = dir
            };
            await Task.Run(() => Run(info));
        }

        private static async Task SvnUpdate(string dir)
        {
            var info = new ProcessStartInfo("svn")
            {
                CreateNoWindow = true,
                Arguments = "update",
                RedirectStandardError = true,
                RedirectStandardOutput = true,
                UseShellExecute = false,
                WorkingDirectory = dir
            };
            info.Environment.Add("LC_ALL", "en_US.UTF-8");
            info.Environment.Add("LANG", "en_US.UTF-8");
            info.Environment.Add("LANGUAGE", "en_US.UTF-8");
            await Task.Run(() => Run(info));
        }

        private static void Run(ProcessStartInfo info)
        {
            using (var p = new Process { StartInfo = info })
            {
                p.OutputDataReceived += (s, e) =>
                {
                    if (string.IsNullOrWhiteSpace(e.Data)) return;
                    XTrace.WriteLine("[{0}] {1} {2} {3}", info.WorkingDirectory, info.FileName, info.Arguments, e.Data);
                };
                p.ErrorDataReceived += (s, e) =>
                {
                    if (string.IsNullOrWhiteSpace(e.Data)) return;
                    XTrace.WriteLine("[{0}] {1} {2} {3}", info.WorkingDirectory, info.FileName, info.Arguments, e.Data);
                };
                p.Start();
                p.BeginOutputReadLine();
                p.BeginErrorReadLine();
                p.WaitForExit();
            }
        }
        public static int Limit => 10;
        public static bool IsRunning { get; set; } = true;
        private static async Task Run()
        {
            while (true)
            {
                //删除已完成的
                var remove = Running.RemoveAll(i => i.IsCompleted);
                if (remove > 0)
                {
                    XTrace.WriteLine("移除已完成任务：{0} 条", remove);
                }
                if (Running.Count <= Limit)
                {
                    for (int i = Running.Count; i <= Limit && Queue.TryDequeue(out var func); i++)
                    {
                        XTrace.WriteLine("启动一条新任务");
                        Running.Add(func());
                    }
                }
                if (IsRunning)
                {
                    await Task.Delay(300);
                }
                else
                {
                    if (Running.Count == 0)
                    {
                        break;
                    }
                }
            }
        }

        private static void Main(string[] args)
        {
            XTrace.UseConsole();
            var cfg = GitPullerConfiguration.Current;
            var root = cfg.Root;
            XTrace.WriteLine("Root:{0}", root);
            var runTask = Run();
            var queue = new Queue<string>();
            queue.Enqueue(root);
            while (queue.Count > 0)
            {
                var dir = queue.Dequeue();
                XTrace.WriteLine("Scan: {0} ", dir);

                var children = Directory.GetDirectories(dir);
                var isGit = false;
                var isSvn = false;
                var isSkip = false;
                foreach (var child in children)
                {
                    var name = Path.GetFileName(child);
                    if (name == ".skip-pull")
                    {
                        isSkip = true;
                        break;
                    }

                    if (name == ".git" && File.Exists(Path.Combine(child, "index")))
                    {
                        isGit = true;
                        break;
                    }

                    if (name == ".svn" && File.Exists(Path.Combine(child, "format")))
                    {
                        isSvn = true;
                        break;
                    }
                }

                if (isGit)
                {
                    XTrace.WriteLine("{0} is git directory", dir);
                    Queue.Enqueue(() => GitPull(dir));
                }
                else if (isSvn)
                {
                    XTrace.WriteLine("{0} is svn directory", dir);
                    Queue.Enqueue(() => SvnUpdate(dir));
                }
                else if (isSkip)
                {
                    XTrace.WriteLine("Skip {0}", dir);
                }
                else
                {
                    foreach (var child in children) queue.Enqueue(child);
                }
            }
            IsRunning = false;
            Task.WaitAll(runTask);
            XTrace.WriteLine("Done!");
        }
    }
}